package com.ra.landlord;

import java.math.BigInteger;
import java.net.URI;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.persistence.DiscriminatorValue;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletRedirectResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.espirit.eap.ValidationUtil;
import com.espirit.eap.manager.Dictionary;
import com.espirit.eap.manager.DictionaryService;
import com.espirit.eap.manager.SystemLog;
import com.espirit.eap.manager.SystemLogService;
import com.espirit.eap.manager.TaskSchedulerService;
import com.espirit.eap.sa.LoginUser;
import com.espirit.eap.sa.LoginUserService;
import com.espirit.eap.sa.Privilege;
import com.espirit.eap.sa.Template;
import com.espirit.eap.sa.UserTemplate;
import com.espirit.weixin.core.WeixinUtil;
import com.googlecode.cswish.Config;
import com.googlecode.cswish.annotation.Protected;
import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.annotation.cm;
import com.googlecode.cswish.exception.ApplicationException;
import com.googlecode.cswish.model.KeyValue;
import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.model.Reference;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.oosearch.QLParse;
import com.googlecode.cswish.security.LoginCallback;
import com.googlecode.cswish.security.SafeManager;
import com.googlecode.cswish.security.UserTracerService;
import com.googlecode.cswish.security.UserTracerService.UserLogoutEvent;
import com.googlecode.cswish.security.auth.UserInfo;
import com.googlecode.cswish.struts.ContextHolder;
import com.googlecode.cswish.struts.FreemarkerResult;
import com.googlecode.cswish.struts.Initialization;
import com.googlecode.cswish.struts.hibernate.HibernateConfiguration;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.Executor;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ModelModifyEvent;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.ClassUtil;
import com.googlecode.cswish.util.Functions;
import com.googlecode.cswish.util.TagUtil;
import com.googlecode.cswish.util.WebsiteUtil;
import com.googlecode.cswish.util.bean.ModelUtil;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.Result;
import com.ra.external.RoomRetrievalService;
import com.ra.external.WeixinUserService;
import com.ra.order.rental.RentalOrderService;
import com.ra.pay.alipay.AlipayService;
import com.ra.util.RaConstant;
import com.ra.util.SmsLog;
import com.ra.util.SmsService;
import com.ra.weixin.WeixinUser;

@Service
public class LandlordUserService implements Initialization {

	private final static Log logger = LogFactory.getLog(LandlordUserService.class);
	
	private static final String ANONYMITY_USER = "anonymity.free";
	public static final String LANDLORDUSER_ROLE = "LandlordUserRole";
	public static final String TENANTUSER_ROLE = "TenantUserRole";
	private static final String WEIXIN_ROLE = "WeixinUserRole";
	
	public static final String REQ_FROM_WEIXIN = "FromWeiXin";
	
	@Resource
	private LoginUserService loginUserService;
	
	@Resource
	private GenericService genericService;
	
	@Resource
	private ObjectFactory objectFactory;
	
	@Resource
	private SafeManager safeManager;
	
	@Resource
	private ValidationUtil validationUtil;
	
	@Resource
	private WeixinUtil weixinUtil;
	
	@Resource
	private TagUtil tagUtil;
	
	@Resource
	private SmsService smsService;
	
	@Resource
	private UserTracerService userTracerService;
	
	@Resource
	private HibernateConfiguration hibernateConfiguration;
	
	@Resource
	private BeanIntrospector beanIntrospector;
	
	@Resource
	private Config config;
	
	@Resource
	private Functions functions;
	
	@Resource
	private TaskSchedulerService taskSchedulerService;
	
	@Resource
	private WeixinUserService weixinUserService;
	
	@Resource
	private DictionaryService dictionaryService;
	
	@Resource
	private LandlordPurchaseInfoService landlordPurchaseInfoService;
	
	@Resource
	private QLParse qlParse;
	
	@Resource
	private LandlordAssistUserService landlordAssistUserService;

	private LandlordUserService landlordUserService;
	
	@Resource
	private RoomRetrievalService retrievalService;
	
	@Resource
	private SystemLogService systemLogService;
	
	@Resource
	private RentalOrderService rentalOrderService;
	
	@Resource
	private AlipayService alipayService;
	
	// 登录接口被da,ra共用
	private static final String[] PRODUCT_NAME = new String[] {"ra", "da", "ca"};

	// 前端房东APP模块映射
	private static final Map<String, String> clickMapping = new HashMap<String, String>();
	static {
		clickMapping.put("1", "未登录启动APP");
		clickMapping.put("2", "打开注册页面");
		clickMapping.put("3", "登录");
		clickMapping.put("4", "进入收租列表");
		clickMapping.put("5", "进入出租列表");
		clickMapping.put("6", "进入退租列表");
		clickMapping.put("7", "进入楼房管理列表");
		clickMapping.put("8", "进入计费项列表");
		clickMapping.put("9", "进入抄表列表");
		clickMapping.put("10", "进入发布房源");
		clickMapping.put("11", "进入批量打印");
		clickMapping.put("12", "进入财务列表");
		clickMapping.put("13", "进入催租功能");
		clickMapping.put("14", "进入批量创建楼房内容填写");
		clickMapping.put("15", "进入批量创建楼房列表审核");
		clickMapping.put("16", "进入快速注册手机和名字录入页面");
		clickMapping.put("17", "进入快速注册验证码和密码录入页面");
		clickMapping.put("18", "批量创建楼房成功页面");
	}
	
	private LandlordUserService getThis() {
		if (landlordUserService == null) {
			landlordUserService = objectFactory.getBean(LandlordUserService.class, false);
		}
		return landlordUserService;
	}
	
	@Override
	public String[] getProductName() {
		return PRODUCT_NAME;
	}

	@Override
	public void initSite() {
		config.setPageSize(50);			// 设置缺省分页为100, 以支持genericService.search中100*10的最大查询
		
		initRolePermission();
		
		genericService.on(Template.class, GenericService.OPERATION_MERGE, new ModelModifyEvent<Template>() {
			@Override
			public void onMessage(Template newModel, Template oldModel, String operation) {
				updateRolePermission(newModel, oldModel);
			}
		}, true);
		
		safeManager.setLoginCallback(new LoginCallback() {
			
			// 各子帐户的登录权限授予: 房东, 租客, 微信用户
			@Override
			public UserInfo execute(SafeManager safeManager, String userId, String site) {
				// 试图重用现有的登录用户模型: 1) 提高性能   2) 可以避免从微信菜单进入时, 原有的数据丢失
				HttpServletRequest request = null;
				if (ActionContext.getContext() != null) {
					request = ServletActionContext.getRequest();
				}
				boolean isFromWeiXin = request != null && request.getAttribute(REQ_FROM_WEIXIN) != null;
				if (isFromWeiXin) {
					LoginUser existedLoginUser = (LoginUser) safeManager.getUserInfos().get(userId);
					if (existedLoginUser != null) {
						return existedLoginUser;
					}
				}
				
				LoginUser loginUser = loginUserService.loginUserBySite(userId, site, null);
				
				// Don't use 'getThis()' to ensure the transaction is the same transaction
				LandlordUser user = getUserByLoginUser(loginUser.getId(), false);
				UserExtContext userExtContext = new UserExtContext();
				loginUser.setUserEx(userExtContext);
				
				List<String> roles = new ArrayList<String>();
				if (user != null) {
					userExtContext.setLandlordUser(user);
					if (!loginUser.isSuperAdmin()) {
						if (user instanceof LandlordOwnerUser) {
							roles.add(LANDLORDUSER_ROLE);
						} else {
							LoginUser loginUserDb = (LoginUser)genericService.load(LoginUser.class, Integer.valueOf(userId));
							List<Privilege> privilegeList = loginUserDb.getPagePermissions();
							if (CollectionUtils.isEmpty(privilegeList)) {
								roles.add(LANDLORDUSER_ROLE);
							} else {
								for (Privilege privilege : privilegeList) {
									loginUserService.addPagePermission(userId, privilege);
								}
							}
						}
						// 设定用户的Owner
						loginUser.setOwnerUserId(user.getOwnerUser().getId());
					}
				} else {
					if (loginUser.isSuperAdmin()) {
						// 对于super admin， 自动检测和创建房东用户
						user = getThis().loadOrCreateLandlordUserForAdmin();
						user = detachLandlordUser(user);
						userExtContext.setLandlordUser(user);
					}
				}
				
				// weixin
				WeixinUser weixinUser = getThis().getWeixinUserByLoginUser(loginUser.getId(), false);
				if (weixinUser != null) {
					userExtContext.setWeixinUser(weixinUser);
					if (!loginUser.isSuperAdmin()) {
						roles.add(TENANTUSER_ROLE);
					}
				}
				
				if (logger.isWarnEnabled()) {
					if (!userExtContext.hasUserInfo()) {
						logger.warn("Can't find any detail user information for loginUser: " + userId + "(LandlordUser/WeixinUser)");
					}
				}				
				if (roles.size() > 0) {
					loginUser.setRoleIds(roles.toArray(new String[roles.size()]));
				}
				return loginUser;
			}
		});
		
		userTracerService.subscribeLogoutEvent(traceUserLogoutExecutor);
	}

	private void initRolePermission() {
		// Free path
		// 数据字典
		UserTemplate example = new UserTemplate();
		example.setName(ANONYMITY_USER);
		UserTemplate template = genericService.searchAll(example).getData(0);
		if (template != null) {
			updateRolePermission(template, null);
		}
		
		// 房东角色
		userTracerService.login(LANDLORDUSER_ROLE, null);
		example = new UserTemplate();
		example.setName(LANDLORDUSER_ROLE);
		template = genericService.searchAll(example).getData(0);
		if (template != null) {
			updateRolePermission(template, null);
		}
				
		// 租客角色 /微信角色
		userTracerService.login(TENANTUSER_ROLE, null);
		example = new UserTemplate();
		example.setName(TENANTUSER_ROLE);
		template = genericService.searchAll(example).getData(0);
		if (template != null) {
			updateRolePermission(template, null);
		}
	}
	
	private void updateRolePermission(UserTemplate newTemplate, UserTemplate oldTemplate) {
		String site = functions.getSite();
		String name = newTemplate.getName();
		if (ANONYMITY_USER.equals(name)) {
			if (oldTemplate != null && oldTemplate != newTemplate) {
				for (Privilege privilege : oldTemplate.getPagePermissions()) {
					safeManager.removeFreePath(privilege.toPath(site));
				}
			}
			for (Privilege privilege : newTemplate.getPagePermissions()) {
				safeManager.addFreePath(privilege.toPath(site));
			}
		} else {
			if (oldTemplate != null && oldTemplate != newTemplate) {
				for (Privilege privilege : oldTemplate.getPagePermissions()) {
					safeManager.removePagePermission(name, privilege.toPath(site));
				}
			}
			
			for (Privilege privilege : newTemplate.getPagePermissions()) {
				loginUserService.addPagePermission(name, privilege);
			}
		}
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	@Transactional
	public LandlordUser add(LandlordOwnerVIPUser model, String verifyCode, double longitude, double latitude) {
		LandlordUser dbUser = addLandlordUser(model, verifyCode, true);
		landlordPurchaseInfoService.initLandlordUserPurchaseInfo(dbUser);
		return dbUser;
	}

	@Protected
	public LandlordUser addLandlordUser(LandlordUser model, String verifyCode, boolean isCheckVerifyCode)	{
		// create the loginUser
		if (StringUtils.isEmpty(model.getPhone())) {
			throw new ApplicationException("请输入手机号");
		}
		if (validationUtil.hasDuplicateProperty(model)) {
			throw new ApplicationException("该手机号已经被注册,您可以直接登录使用,如忘记密码,可申请重置");
		}
		if (isCheckVerifyCode) {
			String existedVerifyCode = smsService.getVerifyCode(model.getPhone(), false);
			boolean pass = StringUtils.isNotEmpty(existedVerifyCode) && existedVerifyCode.equals(verifyCode);
			if (pass) {
				smsService.removeVerifyCode(model.getPhone());
			} else {
				LoginUser loginUser = loginUserService.getLoginUser();
				if (loginUser == null || !loginUser.isSuperAdmin()) {				
					smsService.reduceTryCount(model.getPhone());
					throw new ApplicationException("手机校验码不正确");
				}
			}
		}
		
		LoginUser example = new LoginUser();
		example.setName(model.getPhone());		// use phone as the login name
		LoginUser dbLoginUser = genericService.searchAll(example).getData(0);
		if (dbLoginUser == null) {
			example.setPassword(model.getPassword());
			dbLoginUser = loginUserService.add(example, null, null);
		} else {
			String newPassword = loginUserService.getEncryptPassword(model.getPassword());
			String oldPassword = dbLoginUser.getPassword();
			if (!StringUtils.equals(newPassword, oldPassword)) {
				throw new ApplicationException("该帐户已经存在，请正确填写原先设定的密码");
			}
		}
		
		LandlordUser dbUser = createLandlordUser(model, dbLoginUser);
		return dbUser;
	}

	// model.name, model.phone, model.password(plain text), model.sex, etc
	private LandlordUser createLandlordUser(LandlordUser model, LoginUser dbLoginUser) {
		enryptPasswordByVcAlgorithm(model);
		model.setLoginUser(dbLoginUser);
		model.setRegister(Calendar.getInstance().getTime());
		model.setPerm(0x000fffff);
		model.setVipType(5);
		if (model.getSourceFrom() == null) {
			// 省缺为Android用户
			model.setSourceFrom(LandlordOwnerVIPUser.SOURCE_FROM_ANDROID);
		}
		// FIXME: 要用update方法， 修正潜在的安全漏洞
		LandlordUser dbUser = genericService.merge(model);
		return dbUser;
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	public boolean checkPhone(String phone) {
		if (StringUtils.isEmpty(phone)) {
			throw new ApplicationException("请输入手机号");
		}
		if (!isMobilePhone(phone)) {
			throw new ApplicationException("手机号码格式不正确");
		}
		
		LoginUser example = new LoginUser();
		example.setName(phone);		// use phone as the login name
		LoginUser dbLoginUser = genericService.searchByModel(example, Condition.SEARCH_ONE).getData(0);
		boolean pass = (dbLoginUser == null);
		if (!pass) {
			throw new ApplicationException("该手机号已经被注册,您可以直接登录使用,如忘记密码,可申请重置");
		}
		return pass;
	}
	
	private boolean isMobilePhone(String mobile) {
		boolean flag = false;
		try {
			Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");
			Matcher m = p.matcher(mobile);
			flag = m.matches();
		} catch (Exception e) {
			flag = false;
		}
		return flag;
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	public boolean checkVerifyCode(String phone, String verifyCode) {
		String existedVerifyCode = smsService.getVerifyCode(phone, false);
		boolean pass = StringUtils.isNotEmpty(existedVerifyCode) && existedVerifyCode.equals(verifyCode);
		if (!pass) {
			throw new ApplicationException("手机校验码不正确");
		}
		return pass;
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	public LandlordUser register(LandlordOwnerVIPUser model, String verifyCode, double longitude, double latitude) {
		LandlordUser dbUser = getThis().add(model, verifyCode, longitude, latitude);
		
		String msg = "感谢使用好好租产品，您的帐号是：" + model.getPhone() + "，请妥善保管！好好租能高效便捷地管理以及推广您的房源，客户服务热线：400-883-0288";
		smsService.sendMessage(model.getPhone(), SmsLog.TYPE_REGISTER_LANDLORD_SUCCESS, msg, true, dbUser.getLoginUser(), SmsService.CHANEL_NORMAL, null);
		
		Integer loginUserId = dbUser.getLoginUser().getId();
		HttpServletRequest request = ServletActionContext.getRequest();
		safeManager.login(request, String.valueOf(loginUserId), ContextHolder.get().getSiteName());
		
		String ip = WebsiteUtil.getRemoteIp(request);
		genericService.executeAsync(traceUserLoginExecutor, new Object[] {dbUser, ip});
		return dbUser;
	}
	
	private void enryptPasswordByVcAlgorithm(LandlordUser model) {
		try {
			// TODO: use the same algorithm with VC program? or use LoginUserService.getEncryptPassword
			byte[] encryptPassword = MessageDigest.getInstance("MD5").digest(model.getPassword().getBytes());
			String base64Password = new String(Hex.encodeHex(encryptPassword));
			model.setPassword(base64Password);
		}  catch (Exception e) {
			logger.error("Failed to encrypt password", e);
		}
	}
	
	/**
	 * 带权限的重置密码，主要为了控制房东管理员的重置密码
	 * @param model
	 * @param verifyCode
	 * @param password
	 * @return
	 */
	@Rest(type="resetPwd")
	public String resetPasswordAuth(LandlordUser model, String verifyCode, String password) 
	{
		return resetPassword(model, verifyCode, password);
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	public String resetPassword(LandlordUser model, String verifyCode, String password) {
		String existedVerifyCode = smsService.getVerifyCode(model.getPhone());
		boolean pass = StringUtils.isNotEmpty(existedVerifyCode) && existedVerifyCode.equals(verifyCode);
		if (!pass) {
			LoginUser loginUser = loginUserService.getLoginUser();
			if (loginUser == null || !loginUser.isSuperAdmin()) {
				if (logger.isDebugEnabled()) {
					logger.debug("Invalid verify code: loginUser.id=" + (loginUser == null ? "" : loginUser.getId()) + 
							", existedVerifyCode=" + existedVerifyCode + ",phone=" + model.getPhone() + ",verifyCode=" + verifyCode);
				}
				smsService.reduceTryCount(model.getPhone());
				throw new ApplicationException("手机校验码不正确");
			}
		}
		if (StringUtils.isEmpty(model.getPhone())) {
			throw new ApplicationException("请输入手机号码");
		}
		
		
		LandlordUser example = new LandlordUser();
		example.setPhone(model.getPhone());
		PageInfo<LandlordUser> pageInfo = genericService.searchAll(example);
		if (pageInfo.getData().size() != 1) {
			throw new ApplicationException("电话号码在系统中不存在,请您先访问注册界面");
		}
		
		// update the new password
		LandlordUser dbUser = pageInfo.getData(0);
		dbUser.setPassword(password);
		getThis().update(dbUser, null);
		safeManager.login(ServletActionContext.getRequest(), String.valueOf(dbUser.getLoginUser().getId()),
				ContextHolder.get().getSiteName());
		return "/index.html";
	}
	
	public LandlordUser _update(LandlordUser model) {
		LandlordUser dbModel = genericService.view(model);
		// don't show the encrypted password
		model.setPassword(null);
		
		if (dbModel instanceof LandlordAssistUser) {
			LandlordAssistUser landlordAssistUser = (LandlordAssistUser)dbModel;
			if (landlordAssistUser.getLandlordOwnerUser() != null) {
				ActionContext.getContext().getValueStack().setValue("landlordUserId", landlordAssistUser.getLandlordOwnerUser().getId());
			}
			
			ActionContext.getContext().getValueStack().setValue("model", dbModel);
		}
		return model;
	}

	public LandlordUser update(LandlordUser model, Integer landlordUserId) {
		// TODO: 检查电话号码? 不允许修改或者走特定流程修改?
		validationUtil.checkDuplicateModel(model);
		
		String password = model.getPassword();
		boolean changePassword = password != null;
		if (changePassword) {
			enryptPasswordByVcAlgorithm(model);
		} else {
			LandlordUser dbUser = genericService.load(model);
			model.setPassword(dbUser.getPassword());
		}
		LandlordUser dbUser = genericService.update(model);
		
		if (dbUser.getLoginUser() == null) {
			// fix the login user
			LoginUser loginUser = new LoginUser();
			loginUser.setName(dbUser.getPhone());
			LoginUser dbLoginUser = genericService.searchAll(loginUser).getData(0);
			if (dbLoginUser == null) {
				if (password != null) {					
					String javaEncryptPassword = loginUserService.getEncryptPassword(password);
					loginUser.setPassword(javaEncryptPassword);
				} else {
					String javaEncryptPassword = convertVcPasswordToJavaPassword(dbUser.getPassword());
					loginUser.setPassword(javaEncryptPassword);
				}
				dbLoginUser = genericService.merge(loginUser);
			}
			dbUser.setLoginUser(dbLoginUser);
		}
		
		
		if (!StringUtils.equals(dbUser.getPhone(), dbUser.getLoginUser().getName()) || changePassword) {
			LoginUser dbLoginUser = dbUser.getLoginUser();
			dbLoginUser.setName(dbUser.getPhone());
			
			if (changePassword) {
				String javaEncryptPassword = loginUserService.getEncryptPassword(password);
				dbLoginUser.setPassword(javaEncryptPassword);
			}
			dbLoginUser = genericService.merge(dbLoginUser);
		}
		
		if (model.getAdminType() != null) {
			String userType = model.getAdminType().toString();
			List<KeyValue> types = getLandlordUserTypes();
			for (KeyValue type : types) {
				if (type.getKey().equals(userType)) {
					String className = type.getValue();
					int index = className.indexOf('(');
					if (index > 0) {
						className = className.substring(index + 1, className.lastIndexOf(')'));
					}
					if (!model.getClass().getName().equals(className)) {
						Class<?> targetType = ClassUtil.getClass(className);
						Object newModel = genericService.changeModelType(model, targetType);
						
						// 因事务原因, 分两步更改
						if (landlordUserId != null && newModel instanceof LandlordAssistUser) {
							LandlordAssistUser landlordAssistUser = (LandlordAssistUser)newModel;
							LandlordOwnerUser landlordOwnerUser = genericService.load(LandlordOwnerUser.class, landlordUserId);
							landlordAssistUser.setLandlordOwnerUser(landlordOwnerUser);
							genericService.merge(landlordAssistUser);
						}
					}
					
					break;
				}
			}
		}
		
		return dbUser;
	}
	
	public boolean deleteList(List<LandlordUser> results) {
		boolean ret = true;
		if (results != null) {
			for (LandlordUser theModel : results) {
				if (theModel != null) {
					ret &= delete(theModel);
				}
			}
		}
		return ret;
	}
	
	public boolean delete(LandlordUser model) {
		LandlordUser dbModel = genericService.load(model);
		boolean isAdminUser = LoginUser.SUPER_ADMIN.equals(dbModel.getName());
		if (isAdminUser) {
			return false;
		}

		return genericService.delete(dbModel, false);
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	public Result _login(String productLogin, String productLoginDesc, String code) {
		Result result = null;
		HttpServletRequest request = ServletActionContext.getRequest();
		String lastPath =  safeManager.getLastVisitInfo(request);
		
		String openid = null;
		String verifyCode = null;
		if (lastPath != null && lastPath.length() > 0) {
			try {
				List <NameValuePair> parameters = URLEncodedUtils.parse(new URI(lastPath), "utf-8");
				for (NameValuePair nameValuePair : parameters) {
					if ("code".equals(nameValuePair.getName())) {
						code = nameValuePair.getValue();
					} else if ("openid".equals(nameValuePair.getName())) {
						openid = nameValuePair.getValue();
					} else if ("verifyCode".equals(nameValuePair.getName())) {
						verifyCode = nameValuePair.getValue();
					}
				}
			} catch (Exception ex) {
				logger.error("Failed to parse url", ex);
			}
		}
		
		String verifyOpenid = null;
		boolean needCheckOpenId = false;
		// 基于token的单点登录
		if (StringUtils.isNotEmpty(code)) {
			// try to login by the weixin code
			verifyOpenid = weixinUtil.getOpenidByToken(null, null, code);
			if (logger.isDebugEnabled()) {
				if (verifyOpenid == null) {
					logger.debug("open id is null, code=" + code);
				} else {
					logger.debug("open id is " + verifyOpenid);
				}
			}
		} else if (StringUtils.isNotEmpty(verifyCode)) {
			logger.debug("verifyCode=" + verifyCode);
			verifyOpenid = weixinUserService.getOpenIdByVerifyCode(verifyCode);
			needCheckOpenId = true;
		}
		if (verifyOpenid != null) {
			// 1. check the openId from WeixinUser
			WeixinUser weixinUser = new WeixinUser();
			weixinUser.setOpenid(verifyOpenid);
			List<WeixinUser> weixinUserList = genericService.searchAll(weixinUser).getData();
			if (needCheckOpenId) {
				if (weixinUserList.size() != 1) {
					throw new ApplicationException("非法请求");
				}
			}
			
			if (weixinUserList.size() > 0) {
				weixinUser = weixinUserList.get(0);
			} else {
				weixinUser = null;
			}
			if (weixinUser == null) {
				weixinUser = weixinUserService.addWeixinUserByOpenid(verifyOpenid, null);		// TODO: eventKey is null?
			}
			LoginUser loginUser = weixinUser.getLoginUser();
			
			// TODO: 移除.
			// 不应该存在有WeixinUser而无LoginUser, 自动修正老数据, see WeixinUserService.addWeixinUser  
			if (loginUser == null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Found missed login user, fix the WeixinUser automatically, WeixinUser.id=" + weixinUser.getId());
				}
				loginUser = new LoginUser();
				// 状态设为无效，则不可以采用用户名、密码的方式登录，参见LoginUserService.login
				loginUser.setStatus(LoginUser.STATUS_INVALID);
				loginUser.setName(weixinUser.getOpenid());
				weixinUser.setLoginUser(loginUser);
				weixinUser = genericService.merge(weixinUser);
				loginUser = weixinUser.getLoginUser();
			}
			request.setAttribute(REQ_FROM_WEIXIN, Boolean.TRUE);
			boolean ret = safeManager.login(request, loginUser.getLoginId(), ContextHolder.get().getSiteName());
			if (ret) {
				if (lastPath != null) {
					result = new ServletRedirectResult(lastPath);
					objectFactory.autoWireBean(result);
				}
			}
		}
		
		// 未能自动登录(单点), 按访问类型, 切不同的登录入口页面
		if (result == null) {
			loginUserService._login(productLogin, productLoginDesc);
			
			boolean isWeiXinBrowser = false;
			String userAgent = request.getHeader("User-Agent");
			boolean isIphone = false;
			boolean isAndroid = false;
			if (userAgent != null){
				userAgent = userAgent.toLowerCase();
				if (userAgent.indexOf("iphone") != -1) {
					isIphone = true;
				}
				
				if (userAgent.indexOf("android") != -1) {
					isAndroid = true;
				}
			}
			
			if (isIphone || isAndroid) {
				isWeiXinBrowser = true;
			}
			
			boolean isSuperAdminSite = false;
			
			// 专用的后台入口, 使用后台专用登录页面, 调用本服务的login方法
			String adminLink = functions.link("index.admin");
			if (adminLink.equals(lastPath)) {
				isSuperAdminSite = true;
			}
			
			boolean isRedirect = false;
			String path;
			if (isWeiXinBrowser) {
				request.setAttribute("returnURL", lastPath);
				path =  getWeixinAuthorizeUrl(lastPath);
			} else if (isSuperAdminSite){
				path = tagUtil.getGenFtl("ra/landlord/landlordUser._login", true);
			} else {
				String siteName = ContextHolder.get().getSiteName();
				boolean isRaSite =  RaConstant.SITE_NAME.equals(siteName);
				if (isRaSite) {
					// 调用网站对应的登陆服务
					String serverName = request.getServerName();
					if (serverName.startsWith("fd.")) {		// fd.hhz360.com
						path = tagUtil.getGenFtl("da/landlord/daLandlordUser._login", true);
					} else {
						//path = tagUtil.getGenFtl("ra/rent/loginAndRegister._login", true);
						path = tagUtil.getGenFtl("ra/wap/wap._login", true);
					}
				} else {
					if ("da".equals(siteName)) {
						path = tagUtil.getGenFtl("da/landlord/daLandlordUser._login", true);
					} else {
						path = tagUtil.getGenFtl("ca/landlord/landlordUser._login", true);
					}
				}
			}
			
			if (logger.isDebugEnabled()) {
				logger.debug("Forward page to path: " + path);
			}
			
			if (isRedirect) {
				result = new ServletRedirectResult(path);
			} else {
				result = new FreemarkerResult(path);
			}
			objectFactory.autoWireBean(result);
		}
		return result;
	}
	
	private String getWeixinAuthorizeUrl(String urlNoSiteName) {
		String uri = "/ra/wap/wap._login.ftl";
		return functions.getTag().getGenPath(uri);
	}
	
	@Rest(simpleServiceName = "anonymity", type = "free")
	public String login(String name, String password, boolean isEncrypted, String site) {
		if (StringUtils.isEmpty(name)) {
			throw new ApplicationException("请输入用户名");
		}
		
		// TODO: remove it after refactoring VC program
		LandlordUser example = new LandlordUser();
		example.setPhone(name);
		PageInfo<LandlordUser> pageInfo = genericService.searchAll(example);
		LandlordUser dbUser = pageInfo.getData(0);
		if (StringUtils.isNotEmpty(name) && dbUser != null && !hasValidLoginUser(dbUser, name)) {
			LoginUser loginUser = loginUserService.checkAndCreateUser(name, LoginUser.class);
			String loginUserPassword = convertVcPasswordToJavaPassword(dbUser.getPassword());
			loginUser.setPassword(loginUserPassword);
			loginUser = genericService.merge(loginUser);
			dbUser.setLoginUser(loginUser);
			dbUser = genericService.merge(dbUser);
		}
		
		// 登录检测逻辑
		String indexPage = loginUserService.login(name, password, isEncrypted, site);
		LoginUser loginUser = (LoginUser) safeManager.getLoginUser(ServletActionContext.getRequest());
		UserExtContext userExtContext = ((UserExtContext)loginUser.getUserEx());
		if (userExtContext.getLandlordUserId() == null) {
			// 自动创建房东用户, 并设置相关权限
			LoginUser dbLoginUser = genericService.load(loginUser);
			LandlordUser landlordUser = new LandlordOwnerVIPUser();
			landlordUser.setPhone(name);
			landlordUser.setPassword(password);
			
			// 1) set user ext
			LandlordUser dbLandlordUser = createLandlordUser(landlordUser, dbLoginUser);
			userExtContext.setLandlordUser(detachLandlordUser(dbLandlordUser));
			// 2) add user role
			List<String> roles = new ArrayList<>();
			for (String roleId : loginUser.getRoleIds()) {
				roles.add(roleId);
			}
			roles.add(TENANTUSER_ROLE);
			loginUser.setRoleIds(roles.toArray(new String[roles.size()]));
		}
		
		if (dbUser != null) {
			String ip = WebsiteUtil.getRemoteIp(ServletActionContext.getRequest());
			genericService.executeAsync(traceUserLoginExecutor, new Object[] {dbUser, ip});
		}
		return indexPage;		// TODO: use indexPage?
	}
	
	/**
	 * 修正老数据问题: 动态修正房东或房东管理员没有LoginUser的问题
	 * @param landlordUser
	 */
	public void fixNoLoginUser(LandlordAssistUser landlordUser)
	{
		if (!hasValidLoginUser(landlordUser))
		{
			LoginUser loginUser = loginUserService.checkAndCreateUser(landlordUser.getName(), LoginUser.class);
			String loginUserPassword = convertVcPasswordToJavaPassword(landlordUser.getPassword());
			loginUser.setPassword(loginUserPassword);
			loginUser = genericService.merge(loginUser);
			landlordUser.setLoginUser(loginUser);
			genericService.merge(landlordUser);
		}
	}
	
	@Rest(simpleServiceName = "loginUser", type = "free")
	public void logout() {
		loginUserService.logout();
	}
	
	private Executor<Boolean, Object[]> traceUserLoginExecutor = new Executor<Boolean, Object[]>() {
		@Override
		public Boolean execute(Object[] parameters) {
			traceUserLogin((LandlordUser)parameters[0], (String)parameters[1]);
			return Boolean.TRUE;
		}
	};
	private UserLogoutEvent traceUserLogoutExecutor = new UserLogoutEvent() {
		public void execute(String userId, String sessionId) {
			LandlordUser landlordUser = getUserByLoginUser(new Integer(userId), false);
			if (landlordUser != null) {
				LandlordTracer lastLandlordTracer = getLastLandlordTracer(landlordUser);
				if (lastLandlordTracer != null) {
					long t1 = lastLandlordTracer.getLoginTime().getTime();
					long t2 = Calendar.getInstance().getTime().getTime();
					int secondGap = (int)((t2 - t1) / 1000);
					lastLandlordTracer.setSpendTime(secondGap);
					genericService.merge(lastLandlordTracer);
				}
			}
		}
	};
	
	private void traceUserLogin(LandlordUser landlordUser, String ip) {
		LandlordTracer landlordTracer = new LandlordTracer();
		landlordTracer.setIp(ip);
		landlordTracer.setLoginTime(Calendar.getInstance().getTime());
		landlordTracer.setLandlordUser(landlordUser);
		landlordTracer.setComputer("APP");
		
		// find the last login record
		LandlordTracer lastLandlordTracer = getLastLandlordTracer(landlordUser);
		if (lastLandlordTracer != null) {
			landlordTracer.setLastLoginTime(lastLandlordTracer.getLoginTime());
		} else {
			landlordTracer.setLastLoginTime(landlordTracer.getLoginTime());
		}
		genericService.merge(landlordTracer);
	}

	private LandlordTracer getLastLandlordTracer(LandlordUser landlordUser) {
		String ql = "from " + LandlordTracer.class.getName() + " a where a.landlordUser.id=? order by a.loginTime desc";
		QLInfo qlInfo = new QLInfo(ql, true, landlordUser.getId());
		qlInfo.setMaxResults(1);
		LandlordTracer lastLandlordTracer = (LandlordTracer) genericService.searchByQl(qlInfo).getData(0);
		return lastLandlordTracer;
	}

	private boolean hasValidLoginUser(LandlordUser dbUser, String name) {
		return dbUser.getLoginUser() != null && dbUser.getLoginUser().getId() != 0 && name.equals(dbUser.getLoginUser().getName());
	}
	
	/**
	 * 房东是否存在loginUser对象
	 * @param dbUser
	 * @return
	 */
	private boolean hasValidLoginUser(LandlordUser dbUser) {
		return (dbUser.getLoginUser() != null && dbUser.getLoginUser().getId() != 0);
	}
	
	// 注：VC用户只做了MD5转Hex， 未再做自定义加密
	private String convertVcPasswordToJavaPassword(String password) {
		String SEED = "0933324145462219732314329";
		int RADIX = 16;
		BigInteger bi_text;
		try {
			byte[] md5Password = Hex.decodeHex(password.toCharArray());
			String base64Password = Base64.encodeBase64String(md5Password);
			bi_text = new BigInteger(base64Password.getBytes("UTF-8"));
			BigInteger bi_r0 = new BigInteger(SEED);
			BigInteger bi_r1 = bi_r0.xor(bi_text);
			return bi_r1.toString(RADIX);
		} catch (Exception e) {
			logger.error("Failed to convert encrypt password", e);
			return password;
		}
	}
	
	public String convertJavaPasswordToVcPassword(String password) {
		String SEED = "0933324145462219732314329";
		BigInteger bi_text;
		try {
			bi_text = new BigInteger(Hex.decodeHex(password.toCharArray()));
			BigInteger bi_r0 = new BigInteger(SEED);
			BigInteger bi_r1 = bi_r0.xor(bi_text);
			byte[] md5Password = Base64.decodeBase64(bi_r1.toByteArray());
			return new String(Hex.encodeHex(md5Password));
		} catch (Exception e) {
			logger.error("Failed to convert encrypt password", e);
			return password;
		}
	}
	
	@Protected
	public LandlordUser getLoginUser() {
		LoginUser loginUser = loginUserService.getLoginUser();
		LandlordUser user = null;
		if (loginUser != null) {
			user = ((UserExtContext)loginUser.getUserEx()).loadLandlordUser();
		}
		
		if (user != null) {
			user = detachLandlordUser(user);
		}
		return user;
	}
	
	/**
	 * @return
	 */
	@Protected
	public LandlordUser getDbLoginUser() {
		LoginUser loginUser = loginUserService.getLoginUser();
		if (loginUser != null) {
			Integer id = ((UserExtContext)loginUser.getUserEx()).getLandlordUserId();
			return genericService.load(LandlordUser.class, id);
		}
		return null;
	}
	
	@Protected
	@Transactional
	public LandlordOwnerVIPUser loadOrCreateLandlordUserForAdmin() {
		// 1. 查找已经存在的
		LandlordOwnerVIPUser adminLandlordUserExample = new LandlordOwnerVIPUser();
		adminLandlordUserExample.setName(LoginUser.SUPER_ADMIN);
		LandlordOwnerVIPUser adminLandlordUser = genericService.searchAll(adminLandlordUserExample).getData(0);
		if (adminLandlordUser != null) {
			return adminLandlordUser;
		}
		
		// 2. 重建一个新的
		LoginUser adminLoginUser = loginUserService.checkAndCreateUser(LoginUser.SUPER_ADMIN, LoginUser.class);
		
		LandlordOwnerVIPUser landlordUser = new LandlordOwnerVIPUser();
		landlordUser.setPhone("admin");
		landlordUser.setName(adminLoginUser.getName());
		landlordUser.setBirthday(Calendar.getInstance().getTime());
		landlordUser.setRegister(Calendar.getInstance().getTime());
		landlordUser.setCertificateType(0);
		landlordUser.setLoginType(0);
		landlordUser.setVipType(0);
		if (adminLoginUser.getPassword() == null) {
			landlordUser.setPassword("");
		} else {
			String vcPassword = convertJavaPasswordToVcPassword(adminLoginUser.getPassword());
			landlordUser.setPassword(vcPassword);
		}
		landlordUser.setLoginUser(adminLoginUser);
		return genericService.merge(landlordUser);
	}
	
	@Protected
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@SuppressWarnings("unchecked")
	public LandlordUser getUserByLoginUser(Integer loginUserId, boolean showWarning) {
		
		LandlordUser model = new LandlordUser();
		LoginUser loginUser = genericService.load(LoginUser.class, loginUserId);
		model.setLoginUser(loginUser);
		PageInfo<LandlordUser> pageInfo = genericService.searchAll(model);
		
//		String ql = "select a from " + LandlordUser.class.getName() + " a where a.loginUser.id=?";
//		PageInfo<LandlordUser> pageInfo = genericService.searchByQl(new QLInfo(ql, true, loginUserId), true);
		
		if (pageInfo.getTotalCount() != 1) {
			if (showWarning && logger.isWarnEnabled()) {
				logger.warn("Invalid LandlordUser.loginUserId: " + loginUserId + ", return null");
			}
			return null;
		}
		
		LandlordUser user = pageInfo.getData(0);
		LandlordUser cloneUser = detachLandlordUser(user);
		return cloneUser;
	}

	private LandlordUser detachLandlordUser(LandlordUser user) {
		LandlordUser cloneUser = ModelUtil.new0(user.getClass());
		copy(user, cloneUser);
		
		if (user instanceof LandlordAssistUser) {
			LandlordAssistUser landlordAssistUser = (LandlordAssistUser) user;
			LandlordOwnerUser ownerUser = landlordAssistUser.getLandlordOwnerUser();
			
			LandlordOwnerUser cloneLandlordOwnerUser = ModelUtil.new0(ownerUser.getClass());
			copy(ownerUser, cloneLandlordOwnerUser);
			
			((LandlordAssistUser)cloneUser).setLandlordOwnerUser(cloneLandlordOwnerUser);
		}
		return cloneUser;
	}

	private void copy(LandlordUser from, LandlordUser to) {
		to.setId(from.getId());
		to.setName(from.getName());
		to.setPhone(from.getPhone());
		to.setAddress(from.getAddress());
		if (from.getLoginUser() != null) {
			LoginUser loginUser = new LoginUser();
			loginUser.setId(from.getLoginUser().getId());
			to.setLoginUser(loginUser);
		}
	}
	
	@Protected
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@SuppressWarnings("unchecked")
	public TenantUser getTenantUserByLoginUser(Integer loginUserId) {
		String ql = "select a from " + TenantUser.class.getName() + " a where a.loginUser.id=?";
		PageInfo<TenantUser> pageInfo = genericService.searchByQl(new QLInfo(ql, true, loginUserId), true);
		if (pageInfo.getTotalCount() != 1) {
			if (logger.isDebugEnabled()) {
				logger.debug("getTenantUserByLoginUser, Invalid loginUserId: " + loginUserId + ", return null");
			}
			return null;
		}
		
		TenantUser user = pageInfo.getData(0);
		TenantUser cloneUser = new TenantUser();
		ModelUtil.copy(user, cloneUser);
		cloneUser.setAgreements(null);
		cloneUser.setLandlordUser(null);
		
		return cloneUser;
	}
	
	
	@Protected
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@SuppressWarnings("unchecked")
	public WeixinUser getWeixinUserByLoginUser(Integer loginUserId, boolean showWarning) {
		String ql = "select a from " + WeixinUser.class.getName() + " a where a.loginUser.id=?";
		PageInfo<WeixinUser> pageInfo = genericService.searchByQl(new QLInfo(ql, true, loginUserId), true);
		if (pageInfo.getTotalCount() != 1) {
			if (showWarning && logger.isWarnEnabled()) {
				logger.warn("getWeixinUserByLoginUser, Invalid loginUserId: " + loginUserId + ", found records: " + pageInfo.getTotalCount());
			}
			return null;
		}
		
		// WeixinUser weixinUser = 
		/*WeixinUser cloneWeixinUser = new WeixinUser();
		copy(weixinUser, cloneWeixinUser);
		
		TenantUser tenantUser = weixinUser.getTenantUser();
		if (tenantUser != null) {
			TenantUser cloneTenantUser = new TenantUser();
			copy(tenantUser, cloneTenantUser);
			cloneTenantUser.setAgreements(null);
			cloneTenantUser.setLandlordUser(null);
			cloneWeixinUser.setTenantUser(cloneTenantUser);
		}*/
		return pageInfo.getData(0);
	}
	
	public void syncUserPassword(Integer landlordUserId) {
		LandlordUser landlordUser = genericService.load(LandlordUser.class, landlordUserId);
		if (landlordUser != null) {
			String vcPassword = landlordUser.getPassword();
			String javaPassword = convertVcPasswordToJavaPassword(vcPassword);
			LoginUser loginUser = landlordUser.getLoginUser();
			loginUser.setPassword(javaPassword);
			genericService.merge(loginUser);
		}
	}
	
	/**
	 * 通过最近几天查询注册用户
	 * @param dayCount
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<LandlordUser> searchLandlordUserByDate(int dayCount){
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR_OF_DAY, 0);
    	calendar.set(Calendar.MINUTE, 0);
    	calendar.set(Calendar.SECOND, 0);
		calendar.add(Calendar.DATE, - dayCount);
		String ql = "select a from " + LandlordUser.class.getName() + " a where a.register > ? order by a.register desc";
		QLInfo qlInfo = new QLInfo(ql, true, calendar.getTime());
		List<LandlordUser> landlordUsers = genericService.searchByQl(qlInfo, false).getData();
		return landlordUsers;
	}
	
	/**
	 * 用于提供给房东APP查询字典表
	 * 
	 * @param model
	 * @param start
	 * @param limit
	 * @param sort
	 * @param dir
	 * @param oldSearch
	 * @param qlInfoRef
	 * @return
	 */
	public PageInfo<Dictionary> searchDictionaryList(Dictionary model, int start, int limit,
    		String sort, String dir, boolean oldSearch, Reference<QLInfo> qlInfoRef) {
		return dictionaryService.search(model, start, limit, sort, dir, oldSearch, qlInfoRef);
	}
	
	/**
	 * 用于统计www.fangxun360.com的访问统计, PerformanceLog会记录此次访问
	 * 
	 * @param source
	 */
	@Rest(simpleServiceName = "anonymity", type = "free")
	public void click(String source, boolean parseIt) {
		if (parseIt && StringUtils.isNotEmpty(source)) {
			// split source and insert it to PerformanceLog
			try {
				Map map = JSON.parseObject(source);
				String type = (String) map.get("type");
				if ("FDAPP".equals(type)) {
					List<String> event = (List<String>) map.get("event");
					long llocalTime = (Long)map.get("localTime");
					long systemTime = Calendar.getInstance().getTime().getTime();
					long gap = systemTime - llocalTime;
					Calendar clickCal = Calendar.getInstance();
					
					List<SystemLog> logs = new ArrayList<SystemLog>();
					for (String item : event) {
						int index = item.indexOf(':');
						String funcCode = item.substring(0, index);
						String clickTime = item.substring(index + 1);
						long lclickTime = new Long(clickTime) + gap;
						clickCal.setTime(new Date(lclickTime));
						
						String func = clickMapping.get(funcCode);
						if (func != null) {
							SystemLog systemLog = new SystemLog();
							systemLog.setModelName(func);
							systemLog.setCreationOn(clickCal.getTime());
							logs.add(systemLog);
						}
					}
					if (!logs.isEmpty()) {
						systemLogService.addModuleVisitLog(logs);
					}
				}
			} catch (Exception ex) {
				// ignore it
				if (logger.isDebugEnabled()) {
					logger.debug("Wrong format: " + source);
				}
			}
		}
	}
	
	public void addLog(String sourceFrom, String version, String parameter) {
		systemLogService.add("js", sourceFrom + '#' + version, parameter);
	}
	
	/**
	 * 获取当前登录用户的房东（房东）
	 * @return
	 */
	public LandlordOwnerUser getLandlordOwnerUser(){
		LandlordUser landlordUser = landlordUserService.getLoginUser();
		return landlordUser.getOwnerUser();
	}
	
	/**
	 * 获取当前登录用户的房东（房东或房东管理员）
	 * @return
	 */
	public LandlordUser getLandlordUser(){
		return getDbLoginUser();
	}
	
	
	public List<KeyValue> getLandlordUserTypes() {
		List<Class> classes = beanIntrospector.getSubClass(LandlordUser.class.getName());
		List<KeyValue> names = new ArrayList<>(classes.size() + 1);
		cm typeCm = LandlordUser.class.getAnnotation(cm.class);
		String typeName = typeCm == null ? LandlordUser.class.getName() : typeCm.value() + '(' + LandlordUser.class.getName() + ')';
		names.add(new KeyValue(LandlordUser.class.getAnnotation(DiscriminatorValue.class).value(), typeName));
		for (Class<?> clazz : classes) {
			cm cm = clazz.getAnnotation(cm.class);
			String name = cm == null ? clazz.getName() : cm.value() + '(' + clazz.getName() + ')';
			names.add(new KeyValue(clazz.getAnnotation(DiscriminatorValue.class).value(), name));
		}
		return names;
	}
	
	public Integer getRoomCount(Integer landlordUserId) {
		if (landlordUserId == null) {
			return 0;
		}
		
		Room example = new Room();
		LandlordOwnerUser landlordUser = new LandlordOwnerUser();
		landlordUser.setId(landlordUserId);
		example.setLandlordUser(landlordUser);
		QLInfo qlInfo = qlParse.getFromClause(example, Condition.DEFAULT);
		return genericService.getCount(qlInfo, false);
	}
	
	/**
	 * 修改房东银行卡绑定的银行卡信息
	 * cartType:1=银行卡；2=支付宝；3=微信
	 * @param model
	 * @return
	 */
	public List<BankCard> updateLandlordUserBankCard(LandlordUser model){
		List<BankCard> resultBankCards = new ArrayList<>();
		LandlordUser landlordUser = null;
		LoginUser loginUser = loginUserService.getLoginUser();
		if (loginUser != null) {
			Integer id = ((UserExtContext)loginUser.getUserEx()).getLandlordUserId();
			landlordUser = genericService.load(LandlordUser.class, id);
			List<BankCard> bankCards = landlordUser.getBankCards();
			if (bankCards != null) {
				bankCards.clear();
				bankCards.addAll(model.getBankCards());
			}else{
				bankCards = model.getBankCards();
			}
			landlordUser = genericService.merge(landlordUser);
			resultBankCards = landlordUser.getBankCards();
		}
		
		return resultBankCards;
	}
	
	/**
	 * 修改房东信息
	 * @param model
	 * @return
	 */
	public LandlordUser updateLandlordUser(LandlordUser model){
		LandlordUser landlordUser = null;
		LoginUser loginUser = loginUserService.getLoginUser();
		if (loginUser != null) {
			Integer id = ((UserExtContext)loginUser.getUserEx()).getLandlordUserId();
			landlordUser = genericService.load(LandlordUser.class, id);
			if (StringUtils.isNotBlank(model.getName())) {
				landlordUser.setName(model.getName());
			}
			landlordUser = genericService.update(landlordUser);
		}
		return landlordUser;
	}
	
	/**
	 * 验证支付宝帐号是否有效
	 * @return true有效，false无效
	 */
	@Rest(simpleServiceName = "anonymity", type = "free")
	public Result validateAlipayAccount(String alipayAccount, String accountName) {
		return alipayService.validateAlipayAccount(alipayAccount, accountName);
	}
	
	/**
	 * 验证微信帐号是否有效
	 * @return true有效，false无效
	 */
	public boolean validateWeixinAccount(String weixinAccount) {
		return true;
	}
	
}